#include "tcp_server.h"

/*
 * 功能: 服务器构造函数，创建了一个服务器的套接字，并开启端口复用
 *
 * @param paramName 无
 * @return 无
 */

TcpServer::TcpServer()
{
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket == -1)
    {
        std::cerr << "Socket creation failed!" << std::endl;
        exit(1);
    }
    // 开启端口复用功能
    int on = 1;
    setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
}

/*
 * 功能: 服务器的析构函数，清除套接字
 *
 * @param paramName 无
 * @return 无
 */
TcpServer::~TcpServer()
{
    close(server_socket);
}

/*
 * 功能 : 配置服务器, 并且绑定套接字，监听模式，循环监听连接
 *       并创建处理线程，以分离创建。
 * @param paramName ip : 默认参数： "0.0.0.0" 允许任何任何ip地址连接
 * port : 默认参数 : 8080 允许8080的端口连接
 * @ return 无
 */
void TcpServer::startServer(const string &ip , uint16_t port )
{
    sockaddr_in server_addr{};
    server_addr.sin_family = AF_INET;                    // 地址族（ IPv4）
    server_addr.sin_port = htons(port);                  // 端口号
    server_addr.sin_addr.s_addr = inet_addr(ip.c_str()); // 连接的IP地址（INADDR_ANY="0.0.0.0"：表示接受任何IP地址）

    // 绑定套接字
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        cerr << "Bind failed!" << endl;
        exit(1);
    }
    // 开始监听
    if (listen(server_socket, 10) < 0)
    {
        std::cerr << "Listen failed!" << std::endl;
        exit(1);
    }
    std::cout << "Server started. Waiting for devices to register..." << std::endl;
    // 循环来接受客户端连接
    while (true)
    {
        int client_socket = accept(server_socket, NULL, NULL);
        if (client_socket < 0)
        {
            std::cerr << "Accept failed!" << std::endl;
            continue;
        }

        char device_name[50] = {0};
        int ret = read(client_socket, device_name, sizeof(device_name));
        if (ret <= 0)
        {
            std::cerr << "Device registration failed!" << std::endl;
            close(client_socket);
            return;
        }

        if (strncmp(device_name, "reg", 3) == 0)
        {
            string dev_name(&device_name[4]);
            cout << "Device " << dev_name << " registered successfully." << endl;

            Device new_device{
                dev_name,
                client_socket,
            };

            devices.push_back(new_device);
            // Handle this device in a separate thread
            thread(&TcpServer::deviceThread, this, new_device).detach();
        }
        else
        {
            std::cerr << "Device registration failed!" << std::endl;
            close(client_socket);
        }
    }
}

/*
 * 功能: 设备处理函数
 *
 * @param paramName 设备结构体
 * @return 无
 */
void TcpServer::deviceThread(Device device)
{
    char buf[1024] = {0};
    while (true)
    {
        // 这里一个epoll多路复用的对象

        int size = read(device.socket, buf, sizeof(buf));
        if (size <= 0)
        {
            std::cout << "Device " << device.device_name << " disconnected." << std::endl;
            break;
        }
        // 处理函数
    }
    close(device.socket);
    removeDevice(device);
}

void TcpServer::removeDevice(const Device &device)
{
    //使用算法库来遍历查找要删除的设备节点
    auto it = remove_if(devices.begin(), devices.end(), [&device](const Device &d){ return d.socket == device.socket; });
    
    if (it != devices.end())
    {
        devices.erase(it, devices.end());
        std::cout << "Device " << device.device_name << " removed from the list." << std::endl;
    }
}

void TcpServer::showOnlineDevices() 
    {
        std::lock_guard<std::mutex> lock(device_mutex);
        std::cout << "____________Current Online Devices_____________" << std::endl;

        for (const auto& device : devices) {
            struct sockaddr_in addr;
            socklen_t addr_len = sizeof(addr);
            getpeername(device.socket, (struct sockaddr*)&addr, &addr_len);
            char* ip = inet_ntoa(addr.sin_addr);
            int port = ntohs(addr.sin_port);

            std::cout << "Device name: " << device.device_name
                      << ", Socket: " << device.socket
                      << ", IP: " << ip
                      << ", Port: " << port << std::endl;
        }
    }